
#include <assert.h>

#include "Board.hpp"

using namespace Gomoku;

Board::Board(unsigned int size) : _size(size), _board(0)
{
  if (size != 0)
    {
      this->_board = new Color::Type*[this->_size];
      for (unsigned int i = 0; i < this->_size; i++)
	{
	  this->_board[i] = new Color::Type[this->_size];
	  for (unsigned int j = 0; j < this->_size; j++)
	    this->_board[i][j] = Color::NONE;
	}
    }
}

Board::~Board()
{
  if (this->_board != 0)
    {
      for (unsigned int i = 0; i < this->_size; i++)
	if (this->_board[i] != 0)
	  delete [] this->_board[i];
      delete [] this->_board;
    }
}

unsigned int Board::getSize()
{
  return this->_size;
}

Color::Type Board::getCase(unsigned int x, unsigned int y)
{
  assert(this->_board != 0);
  return this->_board[x][y];
}

void Board::setCase(unsigned int x, unsigned int y, Color::Type color)
{
  assert(this->_board != 0);
  if (x < this->_size && y < this->_size)
    this->_board[x][y] = color;
}

bool Board::isPlayable(unsigned int x, unsigned int y)
{
  assert(this->_board != 0);
  assert(x < this->_size && y < this->_size);
  if (x > 0)
    {
      if ((y > 0 && this->_board[x - 1][y - 1] != Color::NONE)
	  || this->_board[x - 1][y] != Color::NONE
	  || (y < (this->_size - 1) && this->_board[x - 1][y + 1] != Color::NONE))
	return true;
    }
  if ((y > 0 && this->_board[x][y - 1] != Color::NONE)
      || (y < (this->_size - 1) && this->_board[x][y + 1] != Color::NONE))
    return true;
  if (x < (this->_size - 1))
    {
      if ((y > 0 && this->_board[x + 1][y - 1] != Color::NONE)
	  || this->_board[x + 1][y] != Color::NONE
	  || (y < (this->_size - 1) && this->_board[x + 1][y + 1] != Color::NONE))
	return true;
    }
  return false;
}

Color::Type Board::getWinner()
{
  for (unsigned int x = 0; x < this->_size; x++)
    {
      for (unsigned int y = 0; y < this->_size; y++)
	{
	  if (this->_board[x][y] != Color::NONE && this->_isWinningLine(x, y))
	    return this->_board[x][y];
	}
    }
  return Color::NONE;
}

bool Board::_isWinningLine(unsigned int x, unsigned int y)
{
  return (this->_checkHorizontal(x, y) 
	  || this->_checkVertical(x, y)
	  || this->_checkDiagonal(x, y));
}

bool Board::_checkHorizontal(unsigned int x, unsigned int y)
{
  assert(x < this->_size && y < this->_size);  

  unsigned int count = 0;
  int cur_x = x;
  Color::Type color = this->_board[x][y];

  while (cur_x >= 0 && this->_board[cur_x][y] == color)
    {
      count++;
      cur_x--;
    }
  cur_x = x + 1;
  while (cur_x < static_cast<int>(this->_size) && this->_board[cur_x][y] == color)
    {
      count++;
      cur_x++;
    }
  if (count >= 5)
    return true;
  return false;
}

  bool Board::_checkVertical(unsigned int x, unsigned int y)
{
  assert(x < this->_size && y < this->_size);

  unsigned int count = 0;
  int cur_y = y;
  Color::Type color = this->_board[x][y];

  while (cur_y >= 0 && this->_board[x][cur_y] == color)
    {
      count++;
      cur_y--;
    }
  cur_y = y + 1;
  while (cur_y < static_cast<int>(this->_size) && this->_board[x][cur_y] == color)
    {
      count++;
      cur_y++;
    }
  if (count >= 5)
    return true;
  return false;
}

bool Board::_checkDiagonal(unsigned int x, unsigned int y)
{
  return false;
}
